#pragma once

#include <vex/core/intrusive_ptr_support.h>
#include <boost/intrusive_ptr.hpp>

namespace vex {
    
    /// <summary> 
    /// Create <c>boost::intrusive_ptr</c> from raw handle pointer received 
    /// as output parameter from a method call.
    /// </summary>
    ///
    /// <param name="p_pointer">
    /// Handle to wrap into <c>boost::intrusive_ptr</c>. Must be a model of handle. 
    /// According to vex reference counting rules the caller must assume that the callee 
    /// had <c>add_ref</c>'d the raw pointer before passing the resource pointer to the caller.
    /// </param>
    template<class THandle> auto as_intrusive_from_out(THandle* p_pointer)
        -> boost::intrusive_ptr<THandle>
    {
        return boost::intrusive_ptr<THandle>(p_pointer, false);
    }

    /// <summary> 
    /// Create <c>boost::intrusive_ptr</c> from raw handle pointer received 
    /// as output parameter from a method call. The type is determined by explicit
    /// template parameter <paramref name="TDesired"/>.
    /// </summary>
    ///
    /// <param name="p_pointer">
    /// Handle to wrap into <c>boost::intrusive_ptr</c>. Must be a model of handle. 
    /// According to vex reference counting rules the caller must assume that the callee 
    /// had <c>add_ref</c>'d the raw pointer before passing the resource pointer to the caller.
    /// </param>
    template<class TDesired, class THandle> auto as_intrusive_of_from_out(THandle* p_pointer)
        -> boost::intrusive_ptr<TDesired> 
    {
        return boost::intrusive_ptr<TDesired>(p_pointer, false);
    }

    template<class TDesired, class THandle> auto as_intrusive_from_in(THandle* p_pointer)
        -> boost::intrusive_ptr<TDesired> 
    {
        return boost::intrusive_ptr<TDesired>(p_pointer, true);
    }
}